In [1]:
## 一般設定

verbose   = False
save_data = False

## 分野の設定
domains = { 'medical'    : True,
            'mce'        : False,
            'economic'   : True,
            'juridical'  : True,
            'publishing' : True }

target_vars = ['word']
target_vars.extend(domains.keys())
print(f"target_vars: {target_vars}")

## 分野の選択
selected_domains = { k:v for k,v in domains.items() if v == True } # as dictionary
print(f"selected domains: {[ k for k, v in selected_domains.items() if v == True ]}")

## domain count balancing
balanced = True
print(f"domain balancing: {balanced}")
target_vars: ['word', 'medical', 'mce', 'economic', 'juridical', 'publishing']
selected domains: ['medical', 'economic', 'juridical', 'publishing']
domain balancing: True
In [2]:
### LDA

import random
random.seed(12345)

## n_topics
n_topics = 5

## doc, term の設定
doc_type           = 'word'
term_size          = 'character'
term_types         = [ '1gram', '2gram', '3gram', 'skippy2gram', 'skippy3gram' ]
term_type          = term_types[1]
ngram_is_inclusive = True
max_doc_length     = 12

## DTM 濾過のための設定
minfreq_val = 3
abuse_threshold_val = 0.03
In [3]:
## colormap
colormap =  [ 'deeppink', 'pink',  'orange', 'green', 'paleturquoise', 'wheat' ]
for d, c in zip(domains, colormap):
    print(f"分野 {d}".ljust(16) + ": " + f"色 {c}")
分野 medical      : 色 deeppink
分野 mce          : 色 pink
分野 economic     : 色 orange
分野 juridical    : 色 green
分野 publishing   : 色 paleturquoise
In [4]:
import sys, os, copy, pickle
import numpy as np
import pandas as pd

データの準備¶

In [5]:
## 保存してあるデータの読み込み
target_dir = "saves"
files = [ f for f in os.listdir(target_dir) if f.endswith(".p") or f.endswith(".dump") ]
#print(files)
#target_file = files[-3] # selects a target file
target_file = "mixed-terms-filtered-2024-01-03-15.p" # publishing x sampled=1
print(f"target file: {target_file}")
target_file_name = os.path.join(target_dir, target_file)
target file: mixed-terms-filtered-2024-01-03-15.p
In [6]:
## Pandas を使って .csv ファイルを開くと実は面倒
#import pandas as pd
#df = pd.read_csv(target_file_name, quotechar='"') ## pandas.csv_read(..) opens a file directly
#df
In [7]:
import pandas as pd
import pickle
with open(target_file_name, 'rb') as pickled:
    df = pickle.load(pickled)
df
Out[7]:
word medical mce economic juridical publishing domain 1gram 2gram 3gram skippy2gram skippy3gram
727 審問 0.0 0.0 0.0 1.0 0.0 3 [審, 問] [審問, 審, 問] [審問, 審問, 審, 問] [審問, 審, 問] [審問, 審問, 審, 問]
332 後頭葉 1.0 0.0 0.0 0.0 0.0 0 [後, 頭, 葉] [後頭, 頭葉, 後, 頭, 葉] [後頭葉, 後頭, 頭葉, 後, 頭, 葉] [後頭, 後…葉, 頭葉, 後, 頭, 葉] [後頭葉, 後頭, 後…葉, 頭葉, 後, 頭, 葉]
435 ISBN 0.0 0.0 0.0 0.0 1.0 4 [I, S, B, N] [IS, SB, BN, I, S, B, N] [ISB, SBN, IS, SB, BN, I, S, B, N] [IS, I…B, I…N, SB, S…N, BN, I, S, B, N] [ISB, IS…N, I…BN, SBN, IS, I…B, I…N, SB, S…N, ...
1224 腸管癒着 1.0 0.0 0.0 0.0 0.0 0 [腸, 管, 癒, 着] [腸管, 管癒, 癒着, 腸, 管, 癒, 着] [腸管癒, 管癒着, 腸管, 管癒, 癒着, 腸, 管, 癒, 着] [腸管, 腸…癒, 腸…着, 管癒, 管…着, 癒着, 腸, 管, 癒, 着] [腸管癒, 腸管…着, 腸…癒着, 管癒着, 腸管, 腸…癒, 腸…着, 管癒, 管…着, ...
577 前方脱臼 1.0 0.0 0.0 0.0 0.0 0 [前, 方, 脱, 臼] [前方, 方脱, 脱臼, 前, 方, 脱, 臼] [前方脱, 方脱臼, 前方, 方脱, 脱臼, 前, 方, 脱, 臼] [前方, 前…脱, 前…臼, 方脱, 方…臼, 脱臼, 前, 方, 脱, 臼] [前方脱, 前方…臼, 前…脱臼, 方脱臼, 前方, 前…脱, 前…臼, 方脱, 方…臼, ...
... ... ... ... ... ... ... ... ... ... ... ... ...
68 婚姻届 0.0 0.0 0.0 1.0 0.0 3 [婚, 姻, 届] [婚姻, 姻届, 婚, 姻, 届] [婚姻届, 婚姻, 姻届, 婚, 姻, 届] [婚姻, 婚…届, 姻届, 婚, 姻, 届] [婚姻届, 婚姻, 婚…届, 姻届, 婚, 姻, 届]
103 ジャパンバッシング 0.0 0.0 1.0 0.0 0.0 2 [ジ, ャ, パ, ン, バ, ッ, シ, ン, グ] [ジャ, ャパ, パン, ンバ, バッ, ッシ, シン, ング, ジ, ャ, パ, ン, バ... [ジャパ, ャパン, パンバ, ンバッ, バッシ, ッシン, シング, ジャ, ャパ, パン... [ジャ, ジ…パ, ジ…ン, ジ…バ, ジ…ッ, ジ…シ, ジ…グ, ャパ, ャ…ン, ャ…... [ジャパ, ジャ…ン, ジャ…バ, ジャ…ッ, ジャ…シ, ジャ…グ, ジ…パン, ジ…パ…...
1307 胸骨挫傷 1.0 0.0 0.0 0.0 0.0 0 [胸, 骨, 挫, 傷] [胸骨, 骨挫, 挫傷, 胸, 骨, 挫, 傷] [胸骨挫, 骨挫傷, 胸骨, 骨挫, 挫傷, 胸, 骨, 挫, 傷] [胸骨, 胸…挫, 胸…傷, 骨挫, 骨…傷, 挫傷, 胸, 骨, 挫, 傷] [胸骨挫, 胸骨…傷, 胸…挫傷, 骨挫傷, 胸骨, 胸…挫, 胸…傷, 骨挫, 骨…傷, ...
2279 麻痺性歩行 1.0 0.0 0.0 0.0 0.0 0 [麻, 痺, 性, 歩, 行] [麻痺, 痺性, 性歩, 歩行, 麻, 痺, 性, 歩, 行] [麻痺性, 痺性歩, 性歩行, 麻痺, 痺性, 性歩, 歩行, 麻, 痺, 性, 歩, 行] [麻痺, 麻…性, 麻…歩, 麻…行, 痺性, 痺…歩, 痺…行, 性歩, 性…行, 歩行,... [麻痺性, 麻痺…歩, 麻痺…行, 麻…性歩, 麻…性…行, 麻…歩行, 痺性歩, 痺性…行...
154 買掛金 0.0 0.0 0.0 1.0 0.0 3 [買, 掛, 金] [買掛, 掛金, 買, 掛, 金] [買掛金, 買掛, 掛金, 買, 掛, 金] [買掛, 買…金, 掛金, 買, 掛, 金] [買掛金, 買掛, 買…金, 掛金, 買, 掛, 金]

1997 rows × 12 columns

In [8]:
## 列名 domain を変更し,文字列としての domain を追加
df = df.rename(columns = {'domain': 'domain_id'})
df['domain'] = [ list(domains.keys())[i] for i in df['domain_id'] ]
df
Out[8]:
word medical mce economic juridical publishing domain_id 1gram 2gram 3gram skippy2gram skippy3gram domain
727 審問 0.0 0.0 0.0 1.0 0.0 3 [審, 問] [審問, 審, 問] [審問, 審問, 審, 問] [審問, 審, 問] [審問, 審問, 審, 問] juridical
332 後頭葉 1.0 0.0 0.0 0.0 0.0 0 [後, 頭, 葉] [後頭, 頭葉, 後, 頭, 葉] [後頭葉, 後頭, 頭葉, 後, 頭, 葉] [後頭, 後…葉, 頭葉, 後, 頭, 葉] [後頭葉, 後頭, 後…葉, 頭葉, 後, 頭, 葉] medical
435 ISBN 0.0 0.0 0.0 0.0 1.0 4 [I, S, B, N] [IS, SB, BN, I, S, B, N] [ISB, SBN, IS, SB, BN, I, S, B, N] [IS, I…B, I…N, SB, S…N, BN, I, S, B, N] [ISB, IS…N, I…BN, SBN, IS, I…B, I…N, SB, S…N, ... publishing
1224 腸管癒着 1.0 0.0 0.0 0.0 0.0 0 [腸, 管, 癒, 着] [腸管, 管癒, 癒着, 腸, 管, 癒, 着] [腸管癒, 管癒着, 腸管, 管癒, 癒着, 腸, 管, 癒, 着] [腸管, 腸…癒, 腸…着, 管癒, 管…着, 癒着, 腸, 管, 癒, 着] [腸管癒, 腸管…着, 腸…癒着, 管癒着, 腸管, 腸…癒, 腸…着, 管癒, 管…着, ... medical
577 前方脱臼 1.0 0.0 0.0 0.0 0.0 0 [前, 方, 脱, 臼] [前方, 方脱, 脱臼, 前, 方, 脱, 臼] [前方脱, 方脱臼, 前方, 方脱, 脱臼, 前, 方, 脱, 臼] [前方, 前…脱, 前…臼, 方脱, 方…臼, 脱臼, 前, 方, 脱, 臼] [前方脱, 前方…臼, 前…脱臼, 方脱臼, 前方, 前…脱, 前…臼, 方脱, 方…臼, ... medical
... ... ... ... ... ... ... ... ... ... ... ... ... ...
68 婚姻届 0.0 0.0 0.0 1.0 0.0 3 [婚, 姻, 届] [婚姻, 姻届, 婚, 姻, 届] [婚姻届, 婚姻, 姻届, 婚, 姻, 届] [婚姻, 婚…届, 姻届, 婚, 姻, 届] [婚姻届, 婚姻, 婚…届, 姻届, 婚, 姻, 届] juridical
103 ジャパンバッシング 0.0 0.0 1.0 0.0 0.0 2 [ジ, ャ, パ, ン, バ, ッ, シ, ン, グ] [ジャ, ャパ, パン, ンバ, バッ, ッシ, シン, ング, ジ, ャ, パ, ン, バ... [ジャパ, ャパン, パンバ, ンバッ, バッシ, ッシン, シング, ジャ, ャパ, パン... [ジャ, ジ…パ, ジ…ン, ジ…バ, ジ…ッ, ジ…シ, ジ…グ, ャパ, ャ…ン, ャ…... [ジャパ, ジャ…ン, ジャ…バ, ジャ…ッ, ジャ…シ, ジャ…グ, ジ…パン, ジ…パ…... economic
1307 胸骨挫傷 1.0 0.0 0.0 0.0 0.0 0 [胸, 骨, 挫, 傷] [胸骨, 骨挫, 挫傷, 胸, 骨, 挫, 傷] [胸骨挫, 骨挫傷, 胸骨, 骨挫, 挫傷, 胸, 骨, 挫, 傷] [胸骨, 胸…挫, 胸…傷, 骨挫, 骨…傷, 挫傷, 胸, 骨, 挫, 傷] [胸骨挫, 胸骨…傷, 胸…挫傷, 骨挫傷, 胸骨, 胸…挫, 胸…傷, 骨挫, 骨…傷, ... medical
2279 麻痺性歩行 1.0 0.0 0.0 0.0 0.0 0 [麻, 痺, 性, 歩, 行] [麻痺, 痺性, 性歩, 歩行, 麻, 痺, 性, 歩, 行] [麻痺性, 痺性歩, 性歩行, 麻痺, 痺性, 性歩, 歩行, 麻, 痺, 性, 歩, 行] [麻痺, 麻…性, 麻…歩, 麻…行, 痺性, 痺…歩, 痺…行, 性歩, 性…行, 歩行,... [麻痺性, 麻痺…歩, 麻痺…行, 麻…性歩, 麻…性…行, 麻…歩行, 痺性歩, 痺性…行... medical
154 買掛金 0.0 0.0 0.0 1.0 0.0 3 [買, 掛, 金] [買掛, 掛金, 買, 掛, 金] [買掛金, 買掛, 掛金, 買, 掛, 金] [買掛, 買…金, 掛金, 買, 掛, 金] [買掛金, 買掛, 買…金, 掛金, 買, 掛, 金] juridical

1997 rows × 13 columns

In [9]:
## diction = dtm を構築

bots = df[term_type] # bot = bag-of-terms

from gensim.corpora.dictionary import Dictionary
diction = Dictionary(bots)

## 結果の確認
print(diction)
Dictionary<5332 unique tokens: ['問', '審', '審問', '後', '後頭']...>
In [10]:
## diction の濾過

import copy
diction_copy = copy.deepcopy(diction) # 予備の生成

## 対象とする語の最低頻度: documents の数が少ない場合は小さくても良い
print(f"minfreq_val: {minfreq_val}")

## 過剰使用 term の濾過
print(f"abuse_threshold_val: {abuse_threshold_val}")

## filter適用: 実は諸刃の刃で,token数が少ない時には適用しない方が良い
apply_filter = True
if apply_filter:
    diction_copy.filter_extremes(no_below = minfreq_val, no_above = abuse_threshold_val)

## check
print(diction_copy) # 中身を見るには print(..) が必要
minfreq_val: 3
abuse_threshold_val: 0.03
Dictionary<1356 unique tokens: ['問', '審', '後', '後頭', '葉']...>
In [11]:
### gensim の用 corpusの構築

## データを選択
diction = diction_copy # 名前を元に戻す

## corpus構築
corpus = [ diction.doc2bow(bot) for bot in bots ]

print(f"Number of documents: {len(corpus)}")
Number of documents: 1997
In [12]:
## LDA モデルの構築

from gensim.models import LdaModel

## LDAモデル
lda = LdaModel(corpus, id2word = diction, num_topics = n_topics, alpha = 0.01)

print(lda) # 中身を見るには print(..) が必要
LdaModel<num_terms=1356, num_topics=5, decay=0.5, chunksize=2000>
In [13]:
%%capture --no-display

## lda のtopic ごとに,関連度の高い term を表示
#
import pandas as pd

n_terms = 20 # topic ごとに表示する term 数の指定
topic_dfs = [ ]
for topic in range(n_topics):
    terms = [ ]
    for i, prob in lda.get_topic_terms(topic, topn = n_terms):
        terms.append(diction.id2token[ int(i) ])
    #
    topic_dfs.append(pd.DataFrame([terms], index = [ f'topic {topic+1}' ]))
#
topic_term_df = pd.concat(topic_dfs)

## Table で表示
topic_term_df.T
Out[13]:
topic 1 topic 2 topic 3 topic 4 topic 5
0 腫 ク ル ラ 産
1 炎 ア 判 経 本
2 瘍 腫 行 イ 業
3 金 機 シ 紙 傷
4 腫瘍 金 イ 済 合
5 権 ック 裁判 保 資
6 紙 タ 裁 フ 会
7 証 腫瘍 分 中 炎
8 場 瘍 人 管 ア
9 P レ 産 経済 人
10 大 デ 紙 ロ 経
11 定 定 ール 折 機
12 下 損 脱 者 プ
13 市場 イ バ ム リ
14 膜 先 外 国 挫
15 市 議 管 折り 取
16 腸 天性 代 症 生
17 自 天 理 機 化
18 子 先天 ド 表 ジ
19 付 ロ 務 護 権
In [14]:
%%capture --no-display

## pyLDAvis を使った結果 LDA の可視化: 階層クラスタリングより詳しい

import pyLDAvis
installed_version = pyLDAvis.__version__
print(f"pyLDAvis installed version: {installed_version}")

if float(installed_version[:3]) > 3.1:
    import pyLDAvis.gensim_models as gensimvis
else:
    import pyLDAvis.gensim as gensimvis
#
pyLDAvis.enable_notebook()

#
lda_used     = lda
corpus_used  = corpus
diction_used = diction

## 実行パラメター
use_tSNE = False
if use_tSNE:
    vis = gensimvis.prepare(lda_used, corpus_used, diction_used, mds = 'tsne', n_jobs = 1, sort_topics = False)
else:
    vis = gensimvis.prepare(lda_used, corpus_used, diction_used, n_jobs = 1, sort_topics = False)
#
pyLDAvis.display(vis)

## 結果について
## topic を表わす円の重なりが多いならn_topics が多過ぎる可能性がある.
## ただし2Dで重なっていても,3Dなら重なっていない可能性もある
Out[14]:
In [15]:
## documents のエンコード

print(f"get encodings using term_type: {term_type}")

check = False
encoding = [ ]
for i, row in df.iterrows():
    if check:
        print(f"row: {row}")
    doc = row[doc_type]
    bot = row[term_type]
    ## get_document_topics(..) では minimu_probability = 0 としないと
    ## 値が十分に大きな topics に関してだけ値が取れる
    enc = lda.get_document_topics(diction.doc2bow(bot), minimum_probability = 0)
    if check:
        print(f"enc: {enc}")
    encoding.append(enc)
#
len(encoding)
get encodings using term_type: 2gram
Out[15]:
1997
In [16]:
random.sample(encoding, 3)
Out[16]:
[[(0, 0.99338764),
  (1, 0.001653086),
  (2, 0.001653086),
  (3, 0.001653086),
  (4, 0.001653086)],
 [(0, 0.0032790129),
  (1, 0.0032790129),
  (2, 0.0032790129),
  (3, 0.0032790129),
  (4, 0.98688394)],
 [(0, 0.0032788506),
  (1, 0.0032788506),
  (2, 0.0032788506),
  (3, 0.0032788506),
  (4, 0.9868846)]]
In [17]:
## df に encoding の列を追加: tuple なので map(..) が必要
df['enc'] = [ list(map(lambda x: x[1], enc)) for enc in encoding ]
if check:
    df

t-SNE を使った可視化¶

In [18]:
%%capture --no-display

## Plotlyを使って tSNE の結果の可視化 (3D)

import sklearn.manifold
import numpy as np
import pandas as pd
import plotly.express as pex

## perplexity の効果を確認
divider = 5
relative_perplexity = True
if relative_perplexity:
    max_val = round(len(df)/divider)
else:
    max_val = 200
perplexity_vals = range(5, max_val, 50) # 10から始めて doc数の 1/divider まで,50づつ大きくする
print(f"perplexity vals: {perplexity_vals}")

E = np.array(list(df['enc']))
for perplexity_val in perplexity_vals:
    ## tSNE 3D の生成
    tSNE_3d_varied = sklearn.manifold.TSNE(n_components = 3, random_state = 0,
                                perplexity = perplexity_val, n_iter = 1000)
    ## Fitting
    model_fitted = tSNE_3d_varied.fit_transform(E)
    
    ## df の編集
    df['tSNE_d1'] = model_fitted[:,0]
    df['tSNE_d2'] = model_fitted[:,1]
    df['tSNE_d3'] = model_fitted[:,2]
    
    ## 描画
    title_val = f"tSNE 3D map (perplex: {perplexity_val}) for {term_type}-based LDA ({n_topics} topics)"
    fig = pex.scatter_3d(df, x = 'tSNE_d1', y = 'tSNE_d2', z = 'tSNE_d3',
                                     color = 'domain', title = title_val)
    #
    fig.update_layout(showlegend = True, legend = {'itemsizing': 'constant'},
                  autosize = False, width = 600, height = 600)
    fig.update_traces(marker_size = 5)
    fig.show()
#

階層クラスタリング¶

In [19]:
## 階層クラスタリングのための事例サンプリング

import os, pickle

## データの再利用のための設定
target_dir = "saves"
signature  = "hc-df-sampled-"
        
## サンプリング処理

reload_df_sampled = True
save_a_new_df     = False # データを更新する時に True にする

## df-sampled.p の最新の版を選ぶ
target_p_fname = [ f for f in [ f for f in os.listdir(target_dir)
                               if signature in str(f) ] if f.endswith(".p") or f.endswith(".dump") ][-1]
print(f"target_p_fname: {target_p_fname}")

target_p_fpath = os.path.join(target_dir, target_p_fname)
with open(target_p_fpath, 'rb') as data:
    print(f"loading pickle: {target_p_fpath}")
    df_sampled_reloaded = pickle.load(data)

##
df_size = len(df)
hc_sampling_rate = 0.1 # 変更可能: 大きくし過ぎると図が見にくい

if reload_df_sampled:
    df_sampled = df_sampled_reloaded
else:
    df_sampled = df.sample(round(df_size * hc_sampling_rate))
    ## 保存
    if save_a_new_df:
        import datetime as dt
        ct = dt.datetime.now()
        ## Pandas で .csv として
        hc_sample_fn1 = f"{target_dir}/{signature}{ct.date()}-{str(ct.time())[:2]}" + ".csv"
        ## pickle を .p として
        hc_sample_fn2 = f"{target_dir}/{signature}{ct.date()}-{str(ct.time())[:2]}" + ".p"

        ## reload 用に保存
        import pandas as pd
        df_sampled.to_csv(hc_sample_fn1)
        print(f"saving data to {hc_sample_fn1}")

        ## pickle.dump(..)で
        import pickle
        print(f"saving data to {hc_sample_fn2}")
        with open(hc_sample_fn2, "wb") as f:
            pickle.dump(df_sampled, f)

##
print(f"{len(df_sampled)} rows are sampled (preservation rate: {len(df_sampled)/df_size})")

## domain 事例数の確認
df_sampled['domain'].value_counts()
target_p_fname: hc-df-sampled-2024-01-08-18.p
loading pickle: saves/hc-df-sampled-2024-01-08-18.p
200 rows are sampled (preservation rate: 0.100150225338007)
Out[19]:
domain
juridical     55
publishing    53
medical       52
economic      40
Name: count, dtype: int64
In [20]:
df_sampled.columns
Out[20]:
Index(['word', 'medical', 'mce', 'economic', 'juridical', 'publishing',
       'domain_id', '1gram', '2gram', '3gram', 'skippy2gram', 'skippy3gram',
       'domain', 'enc', 'tSNE_dim1', 'tSNE_dim2', 'tSNE_dim3', 'tSNE_d1',
       'tSNE_d2', 'tSNE_d3'],
      dtype='object')
In [21]:
# df_sampled['enc'] の再エンコード

print(f"get encodings using term_type: {term_type}")

check = False
re_encoding = [ ]
for i, row in df_sampled.iterrows():
    if check:
        print(f"row: {row}")
    doc = row[doc_type]
    bot = row[term_type]
    ## get_document_topics(..) では minimu_probability = 0 としないと
    ## 値が十分に大きな topics に関してだけ値が取れる
    enc = lda.get_document_topics(diction.doc2bow(bot), minimum_probability = 0)
    if check:
        print(f"enc: {enc}")
    re_encoding.append(enc)
#
len(re_encoding)
get encodings using term_type: 2gram
Out[21]:
200
In [22]:
## 値の更新

df_sampled['enc'] = [ enc[-1] for enc in re_encoding ]
df_sampled
Out[22]:
word medical mce economic juridical publishing domain_id 1gram 2gram 3gram skippy2gram skippy3gram domain enc tSNE_dim1 tSNE_dim2 tSNE_dim3 tSNE_d1 tSNE_d2 tSNE_d3
423 経済協力開発機構 0.0 0.0 1.0 0.0 0.0 2 [経, 済, 協, 力, 開, 発, 機, 構] [経済, 済協, 協力, 力開, 開発, 発機, 機構, 経, 済, 協, 力, 開, 発,... [経済協, 済協力, 協力開, 力開発, 開発機, 発機構, 経済, 済協, 協力, 力開,... [経済, 経…協, 経…力, 経…開, 経…発, 経…機, 経…構, 済協, 済…力, 済…... [経済協, 経済…力, 経済…開, 経済…発, 経済…機, 経済…構, 経…協力, 経…協…... economic (4, 0.9963795) -0.889468 3.587598 -6.074296 0.441167 5.105154 -6.267557
288 無償の供与 0.0 0.0 0.0 1.0 0.0 3 [無, 償, の, 供, 与] [無償, 償の, の供, 供与, 無, 償, の, 供, 与] [無償の, 償の供, の供与, 無償, 償の, の供, 供与, 無, 償, の, 供, 与] [無償, 無…の, 無…供, 無…与, 償の, 償…供, 償…与, の供, の…与, 供与,... [無償の, 無償…供, 無償…与, 無…の供, 無…の…与, 無…供与, 償の供, 償の…与... juridical (4, 0.0024695762) -3.545757 0.165245 11.196485 0.645637 -0.993807 9.590157
1583 解離性痙攣 1.0 0.0 0.0 0.0 0.0 0 [解, 離, 性, 痙, 攣] [解離, 離性, 性痙, 痙攣, 解, 離, 性, 痙, 攣] [解離性, 離性痙, 性痙攣, 解離, 離性, 性痙, 痙攣, 解, 離, 性, 痙, 攣] [解離, 解…性, 解…痙, 解…攣, 離性, 離…痙, 離…攣, 性痙, 性…攣, 痙攣,... [解離性, 解離…痙, 解離…攣, 解…性痙, 解…性…攣, 解…痙攣, 離性痙, 離性…攣... medical (4, 0.0019805208) -5.195769 0.875163 10.695466 1.265129 -1.089723 9.310182
186 法律 0.0 0.0 0.0 1.0 0.0 3 [法, 律] [法律, 法, 律] [法律, 法律, 法, 律] [法律, 法, 律] [法律, 法律, 法, 律] juridical (4, 0.9619035) -3.709284 1.799311 9.029003 1.528853 -0.614401 7.991788
286 原動機付自転車 0.0 0.0 0.0 1.0 0.0 3 [原, 動, 機, 付, 自, 転, 車] [原動, 動機, 機付, 付自, 自転, 転車, 原, 動, 機, 付, 自, 転, 車] [原動機, 動機付, 機付自, 付自転, 自転車, 原動, 動機, 機付, 付自, 自転, ... [原動, 原…機, 原…付, 原…自, 原…転, 原…車, 動機, 動…付, 動…自, 動…... [原動機, 原動…付, 原動…自, 原動…転, 原動…車, 原…機付, 原…機…自, 原…機... juridical (4, 0.0014185993) -11.784619 -0.325288 -2.493599 -7.042899 1.153939 -3.663888
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
20 再尋問 0.0 0.0 0.0 1.0 0.0 3 [再, 尋, 問] [再尋, 尋問, 再, 尋, 問] [再尋問, 再尋, 尋問, 再, 尋, 問] [再尋, 再…問, 尋問, 再, 尋, 問] [再尋問, 再尋, 再…問, 尋問, 再, 尋, 問] juridical (4, 0.99012214) -0.340096 4.730021 -8.098212 1.014942 5.923972 -7.467928
684 再審開始の決定 0.0 0.0 0.0 1.0 0.0 3 [再, 審, 開, 始, の, 決, 定] [再審, 審開, 開始, 始の, の決, 決定, 再, 審, 開, 始, の, 決, 定] [再審開, 審開始, 開始の, 始の決, の決定, 再審, 審開, 開始, 始の, の決, ... [再審, 再…開, 再…始, 再…の, 再…決, 再…定, 審開, 審…始, 審…の, 審…... [再審開, 再審…始, 再審…の, 再審…決, 再審…定, 再…開始, 再…開…の, 再…開... juridical (4, 0.001242426) 0.622073 -5.726269 4.697803 -4.591144 -1.519487 3.482471
1719 二酸化硫黄 1.0 0.0 0.0 0.0 0.0 0 [二, 酸, 化, 硫, 黄] [二酸, 酸化, 化硫, 硫黄, 二, 酸, 化, 硫, 黄] [二酸化, 酸化硫, 化硫黄, 二酸, 酸化, 化硫, 硫黄, 二, 酸, 化, 硫, 黄] [二酸, 二…化, 二…硫, 二…黄, 酸化, 酸…硫, 酸…黄, 化硫, 化…黄, 硫黄,... [二酸化, 二酸…硫, 二酸…黄, 二…化硫, 二…化…黄, 二…硫黄, 酸化硫, 酸化…黄... medical (4, 0.6628161) -6.215843 -8.655442 -1.292019 -1.936142 -7.364551 -0.270393
309 情報通信技術 0.0 0.0 1.0 0.0 0.0 2 [情, 報, 通, 信, 技, 術] [情報, 報通, 通信, 信技, 技術, 情, 報, 通, 信, 技, 術] [情報通, 報通信, 通信技, 信技術, 情報, 報通, 通信, 信技, 技術, 情, 報,... [情報, 情…通, 情…信, 情…技, 情…術, 報通, 報…信, 報…技, 報…術, 通信... [情報通, 情報…信, 情報…技, 情報…術, 情…通信, 情…通…技, 情…通…術, 情…... economic (4, 0.0012423721) 0.278325 9.021332 -0.354943 -1.224211 5.758813 -0.543923
19 自判 0.0 0.0 0.0 1.0 0.0 3 [自, 判] [自判, 自, 判] [自判, 自判, 自, 判] [自判, 自, 判] [自判, 自判, 自, 判] juridical (4, 0.00487846) -4.516312 -8.271256 0.241443 -2.331135 -6.861013 -0.056306

200 rows × 20 columns

In [23]:
## doc 階層クラスタリングの実行

from scipy.cluster.hierarchy import dendrogram, linkage

## 距離行列の生成

## 生データから
doc_linkage_plain = linkage(list(df_sampled['enc']), method = 'ward', metric = 'euclidean')

import numpy as np
import plotly
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "Hiragino sans" # 日本語表示のための設定

## 描画サイズの指定
plt.figure(figsize = (7, round(10 * len(df_sampled) * 0.015))) # This needs to be run here, before dendrogram construction.

## 事例ラベルの生成
label_vals = [ x[:max_doc_length] for x in list(df_sampled[doc_type]) ] # truncate doc keys

## 樹状分岐図の作成
dendrogram(doc_linkage_plain, orientation = 'left', labels = label_vals, leaf_font_size = 7)
plt.title(f"Hierarchical clustering of {len(df_sampled)} (= {100 * hc_sampling_rate}% sample) docs\n\
from {', '.join(selected_domains.keys())} domains with encodings via {term_type}-based LDA ({n_topics} topics)")

## ラベルに domain に対応する色を付ける
ax = plt.gca()
for ticker in ax.get_ymajorticklabels():
    word = ticker.get_text()
    row = df_sampled.loc[df_sampled[doc_type] == word]
    try:
        domain_id = int(row['domain_id'])
    except TypeError:
        pass
    ticker.set_color(plotly.colors.qualitative.Plotly[domain_id + 1]) # id の基数調整
#
plt.show()
/var/folders/s2/lk8hdt6j10j0xyycw1lbjsm40000gn/T/ipykernel_57482/3355956744.py:32: FutureWarning:

Calling int on a single element Series is deprecated and will raise a TypeError in the future. Use int(ser.iloc[0]) instead

No description has been provided for this image
In [ ]: